﻿/*Copyright (C) 2010-2012 RAAFCOM B.V. All rights reserved.

This file is part of Velsto and may be used under the terms of:
The GNU General Public License version 3 or higher, as published by
the Free Software Foundation.

This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.*/
/* 
* Application  : Velsto
* Class        : XYPointFile
* 04/06/2010-  : M.A.van Ravesteijn (Raafcom)
*   02/09/2010   Initial version v1.0
* 07/05/2012   : M.A. van Ravesteijn (Raafcom)
*                version 1.1 kriging residuals
* 06-08 2012   : M.A.van Ravesteijn (Raafcom)
*                version 1.2 residual workflow 
* 
* Class for Methods around XY files (file with key XYPointEntity XY Pairs)
*/ 
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.IO;
using System.Globalization;
using System.Drawing;
using System.Windows.Forms;

namespace Velsto
{
    public class XYPointFile
    {
        private cBack cb;
        

        public XYPointFile()
        {
        }

        // Utility Method to parse with both decimal separators
        public double parseDoubleString(string sd)
        {
            var currentCulture = System.Globalization.CultureInfo.InstalledUICulture;
            var numberFormat = (System.Globalization.NumberFormatInfo)
            currentCulture.NumberFormat.Clone();
            numberFormat.NumberDecimalSeparator = ".";
            double number;
            bool succeeded = double.TryParse(sd, System.Globalization.NumberStyles.Any, numberFormat, out number);
            if (succeeded)
            {
                return number;
            }
            else
            {
                numberFormat.NumberDecimalSeparator = ",";
                bool succeeded2 = double.TryParse(sd, System.Globalization.NumberStyles.Any, numberFormat, out number);
                if (succeeded2)
                {
                    return number;
                }
                else
                {
                    return -99999.9;
                }
            }
        }
        
        

        // Method to search nearest Single point and make Single point Joined file
        // Output with . as decimal separator
        public SimulationEntity writeSingleJoinedFile(SimulationEntity se)
        {
            try
            {
                // Read JoinInputfile search nearest XY
                se.JoinSingleFile = se.TempFolderpath + "\\" + "SINGLE_join" + ".join";    
                if (!File.Exists(se.JoinInputFile))
                {
                    se.ErrorMessage = "Cannot Open Joined file " + se.JoinInputFile +
                                      "\r\nSomething may be wrong with the Input Grids" +
                                      "\r\nContact Application Support";
                    return se;
                }
                TextReader readInputFile = new StreamReader(se.JoinInputFile);
                TextWriter writeOutputFile = new StreamWriter(se.JoinSingleFile);
                char[] delimiterChars = { ' ', '\t' };
                XYPointEntity sp = se.SingleSearch;
                double dist = 1.0E50;
                double distCur = 0.0;
                string line = "";
                string lineSingle = "";
                XYPointEntity xy1 = new XYPointEntity();
                XYPointEntity xyFound = new XYPointEntity();
                while ((line = readInputFile.ReadLine()) != null)
                {
                    line = line.Replace(",",".");
                    string[] words = line.Split(delimiterChars,
                                                StringSplitOptions.RemoveEmptyEntries);
                    xy1.X = (int) ((parseDoubleString(words[0]))*10.0);
                    xy1.Y = (int) ((parseDoubleString(words[1]))*10.0);
                    distCur = Math.Pow(xy1.X - sp.X, 2) + Math.Pow(xy1.Y - sp.Y, 2);
                    if (distCur < dist)
                    {
                        xyFound.X = xy1.X;
                        xyFound.Y = xy1.Y;
                        dist = distCur;
                        lineSingle = line;
                    }
                }
                se.SingleFound.X = xyFound.X;
                se.SingleFound.Y = xyFound.Y;
                writeOutputFile.WriteLine(lineSingle);
                readInputFile.Close();
                writeOutputFile.Close();
                return se;
            }
            catch (Exception ex)
            {
                se.ErrorMessage = ex.ToString();
                return se;
            }
        }

        // Method to get parameters for ESRI Ascii grid file from xyGrid
        public SimulationEntity getMapParams(SimulationEntity se,
            string xyFile)
        {
            try
            {
                TextReader readInputFile = new StreamReader(xyFile);
                string line = "";
                string line2 = "";
                double x, y, v, x1, y1, v1;
                double xmin, xmax, ymin, ymax, vmin, vmax, cellsize, czx, czy, cz;
                double meansum;
                int meannr = 0;
                bool nodata = false;
                char[] delimiterChars = { ' ', '\t' };
                line = readInputFile.ReadLine();
                string[] words = line.Split(delimiterChars,
                                                StringSplitOptions.RemoveEmptyEntries);
                x1 = (parseDoubleString(words[0]));
                y1 = (parseDoubleString(words[1]));
                if (se.MapType == Constants.MAP_Z ||
                        se.MapType == Constants.MAP_ZDEV)
                {
                    if (words[1 + se.MapLayernr].Equals("NaN"))
                    {
                        nodata = true;
                        v = 0.0;
                    }
                    else
                    {
                        v = parseDoubleString(words[1 + se.MapLayernr]);
                    }
                }
                else
                {
                    if (words[2].Equals("NaN"))
                    {
                        nodata = true;
                        v = 0.0;
                    }
                    else
                    {
                        v = parseDoubleString(words[2]);
                    }
                }
                                 
                xmin = x1;
                xmax = x1;
                ymin = y1;
                ymax = y1;
                if (!nodata)
                {
                    vmin = v;
                    vmax = v;
                    meansum = v;
                    meannr++;
                }
                else
                {
                    vmin = Constants.MAP_MAX;
                    vmax = Constants.MAP_MIN;
                    meansum = 0.0;
                }
                //minimum cellsize
                double cellmin = 9.9;
                cellsize = 99999;
                while ((line2 = readInputFile.ReadLine()) != null)
                {
                    nodata = false;
                    line2 = line2.Replace(",", ".");
                    string[] words2 = line2.Split(delimiterChars,
                                                StringSplitOptions.RemoveEmptyEntries);
                    x = (parseDoubleString(words2[0]));
                    y = (parseDoubleString(words2[1]));
                    if (se.MapType == Constants.MAP_Z ||
                        se.MapType == Constants.MAP_ZDEV)
                    {
                        if (words2[1 + se.MapLayernr].Equals("NaN"))
                        {
                            nodata = true;
                        }
                        else
                        {
                            v = parseDoubleString(words2[1 + se.MapLayernr]);
                        }
                    }
                    else
                    {
                        if (words2[2].Equals("NaN"))
                        {
                            nodata = true;
                        }
                        else
                        {
                            v = parseDoubleString(words2[2]);
                        }
                    } 
                                           
                    // check cellsize
                    if (x>(x1+cellmin) || x<(x1-cellmin))
                    {
                        cz = Math.Abs(x - x1);
                    }
                    else if (y>(y1+cellmin) || y<(y1-cellmin))
                    {
                        cz = Math.Abs(y - y1);
                    }
                    else
                    {
                        cz = 99999;
                    }
                    cz = Math.Round(cz, 1);
                    if (cz > 9.9)
                    {
                        cellsize = Math.Min(cz, cellsize);
                    }
                    x1 = x;
                    y1 = y;
                    v1 = v;
                    if (x < xmin) xmin = x;
                    if (x > xmax) xmax = x;
                    if (y < ymin) ymin = y;
                    if (y > ymax) ymax = y;
                    if (!nodata)
                    {
                        if (v < vmin) vmin = v;
                        if (v > vmax) vmax = v;
                        meansum = meansum + v;
                        meannr++;
                    }
                }
                se.MapXllcenter = xmin;
                se.MapYllcenter = ymin;
                se.MapNcols = ((int)((xmax - xmin) / cellsize)) + 1;
                se.MapNrows = ((int)((ymax - ymin) / cellsize)) + 1;
                se.MapCellsize = cellsize;
                se.GridXMin = se.MapXllcenter;
                se.GridXMax = se.GridXMin + (se.MapNcols * se.MapCellsize);
                se.GridYMin = se.MapYllcenter;
                se.GridYMax = se.GridYMin + (se.MapNrows * se.MapCellsize);
                se.GridVMin = vmin;
                se.GridVMax = vmax;
                if (meannr > 0)
                {
                    se.GridVMean = meansum / meannr;
                }
                readInputFile.Close();
                se.ErrorMessage = null;
                return se;
            }
            catch (Exception ex)
            {
                se.ErrorMessage = "Error reading Map file\r\n" +
                                  "Input file may contain non numeric characters\r\n" +
                                  "and Check Simulation results Output->Rep";
                //se.ErrorMessage = ex.ToString();
                return se;
            }
        }

        // Method to create input set with control points for kriging from
        // welllayer file making selection on Layer
        public SimulationEntity saveKb2dWellLayerFile(MapWinGIS.Shapefile sp1,SimulationEntity se)
        {
            try
            {
                TextReader readInputFile;
                if (se.MapType == Constants.MAP_ZDEV_WELL || se.MapType == Constants.MAP_ZDEV_WELL2
                    || se.MapType == Constants.MAP_WELL_BULL) 
                {
                    //readInputFile = new StreamReader(se.WellLayerFile);
                }
                else if (se.MapType == Constants.MAP_Z_WELL || se.MapType == Constants.MAP_RES_KRIG)
                {
                    //readInputFile = new StreamReader(se.WellResidualFile);
                }
                else
                {
                    se.ErrorMessage = "Invalid option creating Kriging controlfile";
                    return se;
                }
                TextWriter writeOutputFile = new StreamWriter(se.Kb2dControlPointsFile);
                string line = "";
                char[] delimiterChars = { ' ', '\t' };
                int layer,newInt;
                double x, y, z;
                se.NrWellLayers = 0;
                writeOutputFile.WriteLine("kb2d Control Points");
                writeOutputFile.WriteLine("3");
                writeOutputFile.WriteLine("xlocation");
                writeOutputFile.WriteLine("ylocation");
                writeOutputFile.WriteLine("Primary");
                if (se.MapType == Constants.MAP_ZDEV_WELL)
                {
                    readInputFile = new StreamReader(se.WellLayerFile);
                    while ((line = readInputFile.ReadLine()) != null)
                    {
                        line = line.Replace(",", ".");
                        string[] words = line.Split(delimiterChars,
                                                    StringSplitOptions.RemoveEmptyEntries);
                        if (!int.TryParse(words[0],
                                                 out newInt) || newInt < 0)
                        {
                            se.ErrorMessage = "**ERROR** Layernr in file not integer";
                            readInputFile.Close();
                            writeOutputFile.Close();
                            return se;
                        }
                        layer = newInt;
                        x = parseDoubleString(words[1]);
                        y = parseDoubleString(words[2]);
                        if (layer == se.MapLayernr)
                        {
                            se.Kb2dGo = true;
                            se.NrWellLayers++;
                            writeOutputFile.WriteLine(
                               x.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                               y.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                               "0.0");
                               
                        }
                    }
                    readInputFile.Close();
                    writeOutputFile.Close();
                }
                else if (se.MapType == Constants.MAP_Z_WELL || se.MapType == Constants.MAP_RES_KRIG)
                {
                    double x1 = 0.0, y1 = 0.0, z1 = 0.0 ;
                    for (int i = 0; i < sp1.NumShapes; i++)
                    {
                        sp1.get_Shape(i).get_XY(0, ref x1, ref y1);
                        z1 = (double)sp1.get_CellValue(1, i);
                        if (z1 < Constants.SHP_NODATA)
                        {
                            se.NrWellLayers++;
                            writeOutputFile.WriteLine(
                               x1.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                               y1.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                               z1.ToString("0.0", CultureInfo.InvariantCulture));
                        }
                    }
                    se.Kb2dGo = true;
                    writeOutputFile.Close();
                }
                else if (se.MapType == Constants.MAP_ZDEV_WELL2 || se.MapType == Constants.MAP_WELL_BULL)
                {
                    double x1 = 0.0, y1 = 0.0, z1 = 0.0;
                    for (int i = 0; i < sp1.NumShapes; i++)
                    {
                        sp1.get_Shape(i).get_XY(0, ref x1, ref y1);
                        se.NrWellLayers++;
                        writeOutputFile.WriteLine(
                           x1.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                           y1.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                           "0.0");
                    }
                    se.Kb2dGo = true;
                    writeOutputFile.Close();
                } 
                
                se.ErrorMessage = null;
                return se;
            }
            catch (Exception ex)
            {
                se.ErrorMessage = ex.ToString();
                return se;
            }
        }
        public void shape2File(MapWinGIS.Shapefile s, string fileName, ref SimulationEntity se)
        {
            se.ErrorMessage = null;
            TextWriter writeOutputFile = new StreamWriter(fileName);
            double x=0.0,y=0.0,zo=0.0, z=0.0;
            string w;
            writeOutputFile.WriteLine(Constants.SAVED_DEPTH_FILE_STRING);
            writeOutputFile.WriteLine(se.Rwf_phase.ToString());
            string layerText;
            if (se.AlLayername[se.MapLayernr-1].Equals(""))
            {
                layerText = "Layer " + se.MapLayernr.ToString();
            }
            else
            {
                layerText = "Layer " + (String) se.AlLayername[se.MapLayernr-1];
            }
            string phaseText = "";
            if (se.Rwf_phase == Constants.RWF_PHASE_MARKERS)
            {
                phaseText = "Marker depths";
            }
            else if (se.Rwf_phase == Constants.RWF_PHASE_RESID)
            {
                phaseText = "Residual depths";
            }
            writeOutputFile.WriteLine(se.ProjectName + " " + layerText + " " + phaseText + " " + DateTime.Now.ToString());
            for (int i = 0; i < s.NumShapes; i++)
            {
                s.get_Shape(i).get_XY(0, ref x, ref y);
                zo = (double) s.get_CellValue(0, i);
                z = (double)s.get_CellValue(1, i);
                w = (string)s.get_CellValue(2, i);
                writeOutputFile.WriteLine(
                           x.ToString("0.0", CultureInfo.InvariantCulture) + "\t" +
                           y.ToString("0.0", CultureInfo.InvariantCulture) + "\t" +
                           zo.ToString("0.0", CultureInfo.InvariantCulture) + "\t" +
                           z.ToString("0.0", CultureInfo.InvariantCulture) + "\t" +
                           w);
            }
            writeOutputFile.Close();
            se.File_rwf_phase = se.Rwf_phase;
        }


        public MapWinGIS.Shapefile file2Shape(string fileName, ref SimulationEntity se)
        {
            //
            // Method to convert tvdmarkers file or resuduals file to shapefile
            //
            try
            {
                
                TextReader readInputFile;
                readInputFile = new StreamReader(fileName);
                MapWinGIS.Shapefile sf = new MapWinGIS.Shapefile();
                bool result = sf.CreateNew("", MapWinGIS.ShpfileType.SHP_POINT);
                
                // add depth field original attribute
                MapWinGIS.Field fo = new MapWinGIS.Field();
                fo.Name = "depth_org";
                fo.Precision = 1;
                fo.Type = MapWinGIS.FieldType.DOUBLE_FIELD;
                fo.Width = 8;
                int indfo = 0;
                sf.EditInsertField(fo, ref indfo, null);
                
                // add depth field attribute
                MapWinGIS.Field f = new MapWinGIS.Field();
                f.Name = "depth";
                f.Precision = 1;
                f.Type = MapWinGIS.FieldType.DOUBLE_FIELD;
                f.Width = 8;
                int indf = 1;
                sf.EditInsertField(f, ref indf, null);
                
                // add wellname field attribute
                MapWinGIS.Field w = new MapWinGIS.Field();
                w.Name = "well";
                w.Type = MapWinGIS.FieldType.STRING_FIELD;
                w.Width = 15;
                int indw = 2; 
                sf.EditInsertField(w, ref indw, null);
           
                char[] delimiterChars = {' ','\t'};
                string line;
                string well;
                double x, y, zo, z;
                int inds = 0;
                int i = 0;
                int numpoints = 0;
                bool savedfile = false;
                while ((line = readInputFile.ReadLine()) != null)
                {
                    if (line.Contains(Constants.SAVED_DEPTH_FILE_STRING))
                    {
                        savedfile = true;
                        string line2 = readInputFile.ReadLine();
                        se.File_rwf_phase = Convert.ToInt32(line2);
                        if (se.File_rwf_phase != se.Rwf_phase)
                        {
                            se.ErrorMessage = "Depth file incompatible with workflow phase";
                            return null;
                        }
                        readInputFile.ReadLine();
                    }
                    else
                    {
                        if (!savedfile) { se.File_rwf_phase = se.Rwf_phase; }
                        line = line.Replace(",", ".");
                        string[] words = line.Split(delimiterChars,
                                                    StringSplitOptions.RemoveEmptyEntries);
                        x = parseDoubleString(words[0]);
                        y = parseDoubleString(words[1]);
                        if (savedfile)
                        {
                            zo = parseDoubleString(words[2]);
                            z = parseDoubleString(words[3]);
                            if (words.Length > 4)
                            {
                                well = words[4];
                            }
                            else
                            {
                                well = "";
                            }
                        }
                        else
                        {
                            zo = parseDoubleString(words[2]);
                            z = zo;
                            if (words.Length > 3)
                            {
                                well = words[3];
                            }
                            else
                            {
                                well = "";
                            }
                        }
                        if (x < se.GridXMin || x > se.GridXMax ||
                            y < se.GridYMin || x > se.GridYMax)
                        {
                            MessageBox.Show("Point x="+x.ToString("0.0") + " y=" + y.ToString("0.0") + "\nOutside Grid, discarded");
                        }
                        else
                        {
                            MapWinGIS.Shape s = new MapWinGIS.Shape();
                            s.Create(MapWinGIS.ShpfileType.SHP_POINT);
                            MapWinGIS.Point p = new MapWinGIS.Point();
                            p.x = x;
                            p.y = y;
                            s.InsertPoint(p, ref inds);
                            sf.EditInsertShape(s, ref i);
                            sf.EditCellValue(indfo, i, zo);
                            sf.EditCellValue(indf, i, z);
                            sf.EditCellValue(indw, i, well);
                            i++;
                            numpoints++; 
                            if (numpoints > 2000)
                            {
                                se.ErrorMessage = "Number of depths>2000 probably wrong file";
                                return null;
                            }
                        }
                    }

                }
                if (numpoints < 3)
                {
                    se.ErrorMessage = "Nr of depths must be > 2";
                    return null;
                }
                return sf;
            }
            catch (Exception ex)
            {
                se.ErrorMessage = "Invalid file format check documentation";
                return null;
            }
        }

        public void savedFiletoGridding(ref SimulationEntity se)
        {
            //
            // Method to convert Gridding input(Control file) if saved depth file from
            // Residual workflow
            //
            try
            {
                char[] delimiterChars = { ' ', '\t' };
                string line = null;
                double x = 0, y = 0, z = 0;
                TextReader readInputFile;
                readInputFile = new StreamReader(se.GriddingInFile);
                line = readInputFile.ReadLine();
                if (line.Contains(Constants.SAVED_DEPTH_FILE_STRING))
                {
                    string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".xyz";
                    TextWriter writeOutputFile = new StreamWriter(fileName);
                    string line2 = readInputFile.ReadLine();
                    line2 = readInputFile.ReadLine();
                    while ((line = readInputFile.ReadLine()) != null)
                    {
                        string[] words = line.Split(delimiterChars,
                                                    StringSplitOptions.RemoveEmptyEntries);
                        x = parseDoubleString(words[0]);
                        y = parseDoubleString(words[1]);
                        z = parseDoubleString(words[3]);
                        writeOutputFile.WriteLine(
                            x.ToString("0.0", CultureInfo.InvariantCulture) + "\t" +
                            y.ToString("0.0", CultureInfo.InvariantCulture) + "\t" +
                            z.ToString("0.0", CultureInfo.InvariantCulture));
                    }
                    se.GriddingInFile = fileName;
                    readInputFile.Close();
                    writeOutputFile.Close();
                    return;
                }
                readInputFile.Close();
                return;
            }
            catch (Exception ex)
            {
                se.ErrorMessage = "Invalid file format check documentation";
                return;
            }
        }

        public string controlfileCalculate(string filein, string fileout, int oper, double constant)
        {
            //
            // Method to do basic arithmetic on control points(xyz depth) file.
            //
            string ErrorMessage = null;
            try
            {
                char[] delimiterChars = { ' ', '\t' };
                string line = null;
                double x = 0, y = 0, zorg = 0,z = 0;
                string well = null;
                TextReader readInputFile;
                readInputFile = new StreamReader(filein);
                line = readInputFile.ReadLine();
                // Saved file
                if (line.Contains(Constants.SAVED_DEPTH_FILE_STRING))
                {
                    TextWriter writeOutputFile = new StreamWriter(fileout);
                    writeOutputFile.WriteLine(line);
                    string line2 = readInputFile.ReadLine();
                    writeOutputFile.WriteLine(line2);
                    line2 = readInputFile.ReadLine();
                    writeOutputFile.WriteLine(line2);
                    while ((line = readInputFile.ReadLine()) != null)
                    {
                        string[] words = line.Split(delimiterChars,
                                                    StringSplitOptions.RemoveEmptyEntries);
                        x = parseDoubleString(words[0]);
                        y = parseDoubleString(words[1]);
                        zorg = parseDoubleString(words[2]);
                        z = parseDoubleString(words[3]);
                        if (words.Length > 4)
                        {
                            well = words[4];
                        }
                        else
                        {
                            well = "";
                        }
                        switch (oper)
                        {
                            case Constants.CONTCALCOPER_ADD:
                                zorg = zorg + constant;
                                z = z + constant;
                                break;
                            case Constants.CONTCALCOPER_SUB:
                                zorg = zorg - constant;
                                z = z - constant;
                                break;
                            case Constants.CONTCALCOPER_MULT:
                                zorg = zorg * constant;
                                z = z * constant;
                                break;
                            case Constants.CONTCALCOPER_DIV:
                                zorg = zorg / constant;
                                z = z / constant;
                                break;
                        }
                        writeOutputFile.WriteLine(
                            x.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                            y.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                            zorg.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                            z.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                            well);
                    }

                    readInputFile.Close();
                    writeOutputFile.Close();
                    return null;
                }
                // Normal x y z well file
                else
                {
                    readInputFile.Close();
                    readInputFile = new StreamReader(filein);
                    TextWriter writeOutputFile = new StreamWriter(fileout);
                    while ((line = readInputFile.ReadLine()) != null)
                    {
                        string[] words = line.Split(delimiterChars,
                                                    StringSplitOptions.RemoveEmptyEntries);
                        x = parseDoubleString(words[0]);
                        y = parseDoubleString(words[1]);
                        z = parseDoubleString(words[2]);
                        if (words.Length > 3)
                        {
                            well = words[3];
                        }
                        else
                        {
                            well = "";
                        }
                        switch (oper)
                        {
                            case Constants.CONTCALCOPER_ADD:
                                z = z + constant;
                                break;
                            case Constants.CONTCALCOPER_SUB:
                                z = z - constant;
                                break;
                            case Constants.CONTCALCOPER_MULT:
                                z = z * constant;
                                break;
                            case Constants.CONTCALCOPER_DIV:
                                z = z / constant;
                                break;
                        }
                        writeOutputFile.WriteLine(
                            x.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                            y.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                            z.ToString("0.0", CultureInfo.InvariantCulture) + " " +
                            well);
                    }

                    readInputFile.Close();
                    writeOutputFile.Close();
                    return null;
                }
            }
            catch (Exception ex)
            {
                //ErrorMessage = "Invalid file format check documentation";
                //return ErrorMessage;
                return ex.ToString();
            }
        }
                        
                        
                        
        public List<double> getContourIntervals(int nrContours, double gridMin, double gridMax)
        {
            //
            // Method to determine Contourline values
            //
            // get Contourinterval
            double[] dist = {0.0005,0.001,0.002,0.005,0.01,0.02,0.05,0.1,0.2,0.5,1.0,2.0,5.0,10.0,20.0,50.0,100.0,200.0,
                             500.0,1000.0,2000.0,5000.0,10000.0,20000.0,50000.0};
            double gridInt = gridMax - gridMin;
            bool bFound = false;
            double contourInt = 1.0;
            for (int i = 1; i < dist.Length; i++)
            {
                if ((dist[i] * nrContours >= gridInt) && !bFound)
                {
                    if (i > 0)
                    {
                        contourInt = dist[i - 1];
                    }
                    else
                    {
                        contourInt = dist[0];
                    }
                    bFound = true;
                }
            }
            if (!bFound || contourInt > gridInt / 2.0)
            {
                contourInt = gridInt / nrContours;
                bFound = true;
            }

            // make Contourvalues
            double contourValue = 0.0;
            double temp;
            int i1 = 0;
            int i2 = 0;
            double start_iter = 0.0;
            List<double> ld1 = new List<double>();
            // Get startvalue for negative gridMin
            if (gridMin < 0.0)
            {
                do
                {
                    temp = -1.0 * i1 * contourInt;
                    if (temp < gridMin) start_iter = temp;
                    i1++;
                } while (start_iter > -0.00001 && i1 < 30000);
            }
            // Get Contourvalues
            do
            {
                contourValue = start_iter + (i2 * contourInt);
                if (contourValue >= gridMin && contourValue <= gridMax)
                {
                    ld1.Add(contourValue);
                }
                i2++;
            } while (contourValue < gridMax && i2 < 30000);

            return ld1;
        } 
        
        // Method to create dictionary of xyz file.
        public Dictionary<Point, double> createDict(string xyFile
                                   , int nrLay, ref SimulationEntity se)
        {
            Point xyt = new Point();
            TextReader readXY = new StreamReader(xyFile);
            try
            {
                //read XYfile in Dictionary
                se.ErrorMessage = null;
                string line = null;
                Dictionary<Point, double> sl1 = new Dictionary<Point, double>();
                char[] delimiterChars = { ' ', '\t' };
                double v;
                double vkb2d = 0.0;
                bool nodata = false;
                int i2 = 0;
                int cbmax = se.MapNcols * se.MapNrows;
                
                int ibar = 0;
                int ibar2 = 0;
                while ((line = readXY.ReadLine()) != null)
                {
                    ibar2++;
                    ibar++;
                    if (ibar2 == (int)(cbmax / 20))
                    {
                        if (ibar > cbmax)
                        {
                            cb.Progress("", 100, "Creating Map");
                        }
                        else
                        {
                            cb.Progress(" ", (100 * ibar / (se.MapNcols * se.MapNrows)), "Creating Map");
                        }
                        ibar2 = 0;
                    }

                    line = line.Replace(",", ".");
                    Point xy1 = new Point();
                    string[] words = line.Split(delimiterChars,
                                                StringSplitOptions.RemoveEmptyEntries);
                    // X,Y Int in Decimeters in Dictionary
                    xy1.X = (int)(parseDoubleString(words[0]) * 10.0);
                    xy1.Y = (int)(parseDoubleString(words[1]) * 10.0);
                    nodata = false;
                    if (se.MapType == Constants.MAP_Z ||
                        se.MapType == Constants.MAP_Z_WELL ||
                        se.MapType == Constants.MAP_ZDEV ||
                        se.MapType == Constants.MAP_ZDEV_WELL ||
                        se.MapType == Constants.MAP_ZDEV_WELL2 )
                    {
                        v = parseDoubleString(words[1 + nrLay]);
                    }
                    else
                    {
                        v = parseDoubleString(words[2]);
                    }
                    if (v > Constants.MAP_MAX || v < Constants.MAP_MIN)
                    {
                        nodata = true;
                    }
                    if (!nodata)
                    {
                        xyt = xy1;
                        sl1.Add(xy1, v);
                    }
                }
                readXY.Close();
                return sl1;
            }
            catch (Exception ex)
            {
                readXY.Close();
                se.ErrorMessage = xyt.X.ToString() + " " + xyt.Y.ToString() + ex.ToString();
                return null;
            }
        }
        
        // Method to create inputfile(ESRI ascii grid) for MapWindow
        public void createMapFile(string mapFile, string xyFile
                                   , int nrLay, Dictionary<Point, double> dictkb2d,ref SimulationEntity se)
        {
            Point xyt = new Point();
            cb = new cBack();
            se.ErrorMessage = null;
            TextReader readXY = new StreamReader(xyFile);
            TextWriter writeOutputFile = new StreamWriter(mapFile); 
            try
            {
                string line = null;
                Dictionary<Point, double> dict1 = new Dictionary<Point, double>();
                // create Dictionary for joining
                dict1 = createDict(xyFile, nrLay, ref se);
                // create ESRI ascii grid file  header
                writeOutputFile.WriteLine("ncols " + se.MapNcols.ToString());
                writeOutputFile.WriteLine("nrows " + se.MapNrows.ToString());
                writeOutputFile.WriteLine("xllcenter " +
                               se.MapXllcenter.ToString("0.0", CultureInfo.InvariantCulture));
                writeOutputFile.WriteLine("yllcenter " +
                               se.MapYllcenter.ToString("0.0", CultureInfo.InvariantCulture));
                writeOutputFile.WriteLine("cellsize " +
                               se.MapCellsize.ToString("0.0", CultureInfo.InvariantCulture));
                writeOutputFile.WriteLine("NODATA_value " + Constants.MAP_NODATA);
                cb.Show();
                int ibar = 0;
                int ibar2 = 0;
                int isl = 0;
                int iv = 0;
                double v = 0.0;
                // get values from Dictionary via Point coordinates
                for (int i = se.MapNrows; i > 0; i--)
                {
                    line = "";
                    for (int j = 1; j <= se.MapNcols; j++)
                    {
                        isl++;
                        ibar++;
                        ibar2++;
                        if (ibar2 == (int)((se.MapNrows * se.MapNcols)/ 20))
                        {
                            cb.Progress("", (100 * (((se.MapNrows - i)*se.MapNcols)+j) / (se.MapNcols * se.MapNrows)), "Creating Map");
                            
                            ibar2 = 0;
                        }
                        Point xy2 = new Point();
                        xy2.X = (int)((se.MapXllcenter + ((j - 1) * se.MapCellsize)) * 10.0);
                        xy2.Y = (int)((se.MapYllcenter + ((i - 1) * se.MapCellsize)) * 10.0);

                        Point xy3 = new Point();
                        xy3 = xy2;
                        Point xy4 = new Point();
                        xy4 = xy2;
                        bool nodata = false;
                        double v1 = 0.0;
                        v = 0.0;
                        try
                        {
                            v = dict1[xy2];
                        }
                        catch (KeyNotFoundException ex)
                        {
                            nodata = true;
                        }
                        if (!nodata && se.Kb2dGo && (se.MapType == Constants.MAP_ZDEV_WELL || se.MapType == Constants.MAP_ZDEV_WELL2))
                        {
                            // calibrate uncertainties with kriging variance wells 0->1
                            try
                            {
                                v = dictkb2d[xy3] * v;
                                dict1[xy4] = v;
                                iv++;
                            }
                            catch (KeyNotFoundException ex)
                            {
                                v = v;
                            }
                        }
                        else if (!nodata && se.Kb2dGo && se.MapType == Constants.MAP_WELL_BULL)
                        {
                            // kriging variance wells 0->1
                            try
                            {
                                v = dictkb2d[xy3];
                                dict1[xy4] = v;
                                iv++;
                            }
                            catch (KeyNotFoundException ex)
                            {
                                v = 1.0;
                            }
                        }
                        else if (!nodata && se.Kb2dGo && se.MapType == Constants.MAP_RES_KRIG)
                        {
                            // kriged residuals
                            try
                            {
                                v = dictkb2d[xy3];
                                dict1[xy4] = v;
                                iv++;
                            }
                            catch (KeyNotFoundException ex)
                            {
                                v = 0.0;
                            }
                        }
                        else if (!nodata && se.Kb2dGo && se.MapType == Constants.MAP_Z_WELL)
                        {
                            // add kriged residuals to avz map
                            try
                            {
                                v = dictkb2d[xy3] + v;
                                dict1[xy4] = v;
                                iv++;
                            }
                            catch (KeyNotFoundException ex)
                            {
                                v = v;
                            }
                        }
                        if (nodata || v.ToString().Equals("NaN"))
                        {
                            line = line + " " + Constants.MAP_NODATA;
                        }
                        else
                        {
                            if (v > 100.0 || v < -100.0)
                            {
                                line = line + " " +
                                    v.ToString("0.0", CultureInfo.InvariantCulture);
                            }
                            else if (v > 10.0 || v < -10.0)
                            {
                                line = line + " " +
                                    v.ToString("0.00", CultureInfo.InvariantCulture);
                            }
                            else if (v > 1.0 || v < -1.0)
                            {
                                line = line + " " +
                                    v.ToString("0.000", CultureInfo.InvariantCulture);
                            }
                            else if (v > 0.1 || v < -0.1)
                            {
                                line = line + " " +
                                    v.ToString("0.0000", CultureInfo.InvariantCulture);
                            }
                            else
                            {
                                line = line + " " +
                                    v.ToString("0.000000", CultureInfo.InvariantCulture);
                            }
                        }
                    }
                    writeOutputFile.WriteLine(line);
                }
                writeOutputFile.Close();
                readXY.Close();
                cb.Close();
                return;
            }
            catch (Exception ex)
            {
                writeOutputFile.Close();
                readXY.Close(); 
                se.ErrorMessage = xyt.X.ToString() + " " + xyt.Y.ToString() + ex.ToString();
                return;
            }
        }

        public void createMapFile_array(string mapFile, ref float[,] data
                                   , ref SimulationEntity se)
        {
            cb = new cBack();
            se.ErrorMessage = null;
            TextWriter writeOutputFile = new StreamWriter(mapFile);
            try
            {
                string line = null;
                // create ESRI ascii grid file  header
                writeOutputFile.WriteLine("ncols " + se.MapNcols.ToString());
                writeOutputFile.WriteLine("nrows " + se.MapNrows.ToString());
                writeOutputFile.WriteLine("xllcenter " +
                               se.MapXllcenter.ToString("0.0", CultureInfo.InvariantCulture));
                writeOutputFile.WriteLine("yllcenter " +
                               se.MapYllcenter.ToString("0.0", CultureInfo.InvariantCulture));
                writeOutputFile.WriteLine("cellsize " +
                               se.MapCellsize.ToString("0.0", CultureInfo.InvariantCulture));
                writeOutputFile.WriteLine("NODATA_value " + Constants.MAP_NODATA);
                cb.Show();
                int ibar = 0;
                int ibar2 = 0;
                int isl = 0;
                int iv = 0;
                double v = 0.0;
                // get values from Dictionary via Point coordinates
                for (int i = 0; i < se.MapNrows; i++)
                {
                    line = "";
                    for (int j = 0; j < se.MapNcols; j++)
                    {
                        isl++;
                        ibar++;
                        ibar2++;
                        if (ibar2 == (int)((se.MapNrows * se.MapNcols) / 20))
                        {
                            cb.Progress("", (100 * ((i * se.MapNcols) + j) / (se.MapNcols * se.MapNrows)), "Creating Map");

                            ibar2 = 0;
                        }

                        v = data[i, j];
                        
                        if (v.ToString().Equals("NaN"))
                        {
                            line = line + " " + Constants.MAP_NODATA;
                        }
                        else
                        {
                            if (v > 100.0 || v < -100.0)
                            {
                                line = line + " " +
                                    v.ToString("0.0", CultureInfo.InvariantCulture);
                            }
                            else if (v > 10.0 || v < -10.0)
                            {
                                line = line + " " +
                                    v.ToString("0.00", CultureInfo.InvariantCulture);
                            }
                            else if (v > 1.0 || v < -1.0)
                            {
                                line = line + " " +
                                    v.ToString("0.000", CultureInfo.InvariantCulture);
                            }
                            else if (v > 0.1 || v < -0.1)
                            {
                                line = line + " " +
                                    v.ToString("0.0000", CultureInfo.InvariantCulture);
                            }
                            else
                            {
                                line = line + " " +
                                    v.ToString("0.000000", CultureInfo.InvariantCulture);
                            }
                        }
                    }
                    writeOutputFile.WriteLine(line);
                }
                writeOutputFile.Close();
                cb.Close();
                return;
            }
            catch (Exception ex)
            {
                writeOutputFile.Close();
                se.ErrorMessage = ex.ToString();
                return;
            }
        }
        
        public void readMapFile(int x,string mapFile, int nrows, int ncols, ref float[,,] data, ref SimulationEntity se)
        {
            TextReader readMap = new StreamReader(mapFile);
            try
            {
                char[] delimiterChars = { ' ', '\t' };
                se.ErrorMessage = null;

                // create ESRI ascii grid file  header
                for (int i1 = 1; i1 <= 6; i1++)
                {
                    readMap.ReadLine();
                }

                for (int i = 0; i < nrows; i++)
                {
                    string line = readMap.ReadLine();
                    string[] words = line.Split(delimiterChars,
                                                    StringSplitOptions.RemoveEmptyEntries);
                    for (int j = 0; j < ncols; j++)
                    {
                        data[x, i, j] = (float)parseDoubleString(words[j]);
                    }
                }
                readMap.Close();
            }
            catch (Exception ex)
            {
                readMap.Close();
                se.ErrorMessage = ex.ToString();
            }
        }
 
    }
}
